home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / nr3.c < prev    next >
Text File  |  1989-01-17  |  25KB  |  977 lines

  1. /* net/rom level 3 low level processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "iface.h"
  10. #include "timer.h"
  11. #include "arp.h"
  12. #include "slip.h"
  13. #include "ax25.h"
  14. #include "netrom.h"
  15. #include "nr4.h"
  16. #include "lapb.h"
  17. #include <ctype.h>
  18.  
  19. /* Nodes message broadcast address: "NODES" in shifted ASCII */
  20. struct ax25_addr nr_nodebc = {
  21.     'N'<<1, 'O'<<1, 'D'<<1, 'E'<<1, 'S'<<1, ' '<<1,
  22.     ('0'<<1) | E
  23. } ;
  24.  
  25. struct nriface nrifaces[NRNUMIFACE] ;
  26. unsigned nr_numiface ;
  27. struct nrnbr_tab *nrnbr_tab[NRNUMCHAINS] ;
  28. struct nrroute_tab *nrroute_tab[NRNUMCHAINS] ;
  29. struct nrnf_tab *nrnf_tab[NRNUMCHAINS] ;
  30. unsigned nr_nfmode = NRNF_NOFILTER ;
  31. unsigned nr_ttl = 64 ;
  32. unsigned obso_init = 6 ;
  33. unsigned obso_minbc = 5 ;
  34. unsigned nr_maxroutes = 5 ;
  35. unsigned nr_autofloor = 1 ;
  36. unsigned nr_verbose = 0 ;
  37. struct interface *nr_interface ;
  38.  
  39. /* send a NET/ROM layer 3 datagram */
  40. void nr3output(dest, data)
  41. struct ax25_addr *dest ;
  42. struct mbuf *data ;
  43. {
  44.     struct nr3hdr n3hdr ;
  45.     struct mbuf *n3b ;
  46.  
  47.     n3hdr.dest = *dest ;    /* copy destination field */
  48.     n3hdr.ttl = nr_ttl ;    /* time to live from initializer parm */
  49.  
  50.     if ((n3b = htonnr3(&n3hdr)) == NULLBUF) {
  51.         free_p(data) ;
  52.         return ;
  53.     }
  54.  
  55.     append(&n3b, data) ;
  56.  
  57.     /* The null interface indicates that the packet needs to have */
  58.     /* an appropriate source address inserted by nr_route */
  59.     
  60.     nr_route(n3b,NULLAX25) ;
  61. }
  62.  
  63.  
  64. /* send IP datagrams across a net/rom network connection */
  65. int
  66. nr_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  67. struct mbuf *bp ;
  68. struct interface *interface ;
  69. int32 gateway ;
  70. char precedence ;
  71. char delay ;
  72. char throughput ;
  73. char reliability ;
  74. {
  75.     struct ax25_addr dest ;
  76.     struct mbuf *pbp ;
  77.     struct nr4hdr n4hdr ;
  78.     char *hwaddr ;
  79.     struct arp_tab *arp ;
  80.  
  81.     if ((arp = arp_lookup(ARP_NETROM,gateway)) == NULLARP) {
  82.         free_p(bp) ;    /* drop the packet if no route */
  83.         return ;
  84.     }
  85.     hwaddr = arp->hw_addr ;                /* points to destination */
  86.     memcpy(dest.call, hwaddr, ALEN) ;
  87.     dest.ssid = hwaddr[ALEN] ;
  88.         
  89.     /* Create a "network extension" transport header */
  90.     n4hdr.opcode = NR4OPPID ;
  91.     n4hdr.u.pid.family = PID_IP ;
  92.     n4hdr.u.pid.proto = PID_IP ;
  93.  
  94.     if ((pbp = htonnr4(&n4hdr)) == NULLBUF) {
  95.         free_p(bp) ;
  96.         return ;
  97.     }
  98.  
  99.     append(&pbp,bp) ;        /* Append the data to that */
  100.     nr3output(&dest, pbp) ; /* and pass off to level 3 code */
  101.  
  102. }
  103.  
  104. /* Figure out if a call is assigned to one of my net/rom
  105.  * interfaces.
  106.  */
  107. static int
  108. ismycall(addr)
  109. struct ax25_addr *addr ;
  110. {
  111.     register int i ;
  112.     int found = 0 ;
  113.     
  114.     for (i = 0 ; i < nr_numiface ; i++)
  115.         if (addreq((struct ax25_addr *)(nrifaces[i].interface->hwaddr),
  116.             addr)) {
  117.             found = 1 ;
  118.             break ;
  119.         }
  120.  
  121.     return found ;
  122. }
  123.  
  124.  
  125. /* Route net/rom network layer packets.
  126.  */
  127. nr_route(bp, iaxp)
  128. struct mbuf *bp ;            /* network packet */
  129. struct ax25_cb *iaxp ;        /* incoming ax25 control block */
  130. {
  131.     struct nr3hdr n3hdr ;
  132.     struct nr4hdr n4hdr ;
  133.     struct ax25_cb *axp, *find_ax25(), *open_ax25() ;
  134.     struct ax25 naxhdr ;
  135.     struct ax25_addr neighbor, from ;
  136.     struct mbuf *hbp, *pbp ;
  137.     extern int16 axwindow ;
  138.     void ax_incom() ;
  139.     register struct nrnbr_tab *np ;
  140.     register struct nrroute_tab *rp ;
  141.     register struct nr_bind *bindp ;
  142.     struct nr_bind *find_best();
  143.     struct interface *interface ;
  144.     unsigned ifnum ;
  145.     
  146.     if (ntohnr3(&n3hdr,&bp) == -1) {
  147.         free_p(bp) ;
  148.         return ;
  149.     }
  150.  
  151.     /* If this isn't an internally generated network packet,
  152.      * give the router a chance to record a route back to the
  153.      * sender, in case they aren't in the local node's routing
  154.      * table yet.
  155.      */
  156.  
  157.     if (iaxp != NULLAX25) {
  158.         /* find the interface number */
  159.         for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
  160.             if (iaxp->interface == nrifaces[ifnum].interface)
  161.                 break ;
  162.  
  163.         if (ifnum == nr_numiface) {    /* shouldn't happen! */
  164.             free_p(bp) ;
  165.             return ;
  166.         }
  167.  
  168.         from = iaxp->addr.dest ;
  169.         from.ssid |= E ;
  170.  
  171.         /* Add (possibly) a zero-quality recorded route via */
  172.         /* the neighbor from which this packet was received */
  173.         /* Note that this doesn't work with digipeated neighbors, */
  174.         /* at this point. */
  175.         
  176.         (void) nr_routeadd("      ",&n3hdr.source,ifnum,0,
  177.                                     (char *)&from,0,1) ;
  178.     }
  179.  
  180.     /* A packet from me, to me, can only be one thing: */
  181.     /* a horrible routing loop.  This will probably result */
  182.     /* from a bad manual ARP entry, but we should fix these */
  183.     /* obscure errors as we find them. */
  184.     
  185.     if (ismycall(&n3hdr.dest)) {
  186.         if (iaxp == NULLAX25) {        /* From me? */
  187.             free_p(bp) ;
  188.             return ;
  189.         } else {                    /* It's from somewhere else! */
  190.             if (ntohnr4(&n4hdr,&bp) == -1) {
  191.                 free_p(bp) ;
  192.                 return ;
  193.             }
  194.             if ((n4hdr.opcode & NR4OPCODE) == 0) {
  195.                 if (n4hdr.u.pid.family == PID_IP
  196.                     && n4hdr.u.pid.proto == PID_IP)
  197.                     ip_route(bp,0) ;
  198.                 else                     /* we don't do this proto */
  199.                     free_p(bp) ;
  200.  
  201.                 return ;
  202.             }
  203.             
  204.             /* Must be net/rom transport: */
  205.  
  206.             nr4input(&n4hdr,bp) ;
  207.  
  208.         }
  209.         return ;
  210.     }
  211.  
  212.     if ((rp = find_nrroute(&n3hdr.dest)) == NULLNRRTAB) {
  213.         /* no route, drop the packet */
  214.         free_p(bp) ;
  215.         return ;
  216.     }
  217.  
  218.     if ((bindp = find_best(rp->routes,1)) == NULLNRBIND) {
  219.         /* This shouldn't happen yet, but might if we add */
  220.         /* dead route detection */
  221.         free_p(bp) ;
  222.         return ;
  223.     }
  224.  
  225.     np = bindp->via ;
  226.     memcpy(neighbor.call,np->call,ALEN) ;
  227.     neighbor.ssid = np->call[ALEN] ;
  228.     interface = nrifaces[np->interface].interface ;
  229.  
  230.     /* Now check to see if iaxp is null.  That is */
  231.     /* a signal that the packet originates here, */
  232.     /* so we need to insert the callsign of the appropriate  */
  233.     /* interface */
  234.     if (iaxp == NULLAX25)
  235.         memcpy(&n3hdr.source,interface->hwaddr,AXALEN) ;
  236.     
  237.     /* Make sure there is a connection to the neighbor */
  238.     if ((axp = find_ax25(&neighbor)) == NULLAX25 ||
  239.         (axp->state != CONNECTED && axp->state != RECOVERY)) {
  240.         /* Open a new connection or reinitialize old one */
  241.         /* hwaddr has been advanced to point to neighbor + digis */
  242.         atohax25(&naxhdr, np->call, (struct ax25_addr *)interface->hwaddr) ;
  243.         axp = open_ax25(&naxhdr, axwindow, ax_incom, NULLVFP, NULLVFP,
  244.                         interface,(char *)0) ;
  245.         if (axp == NULLAX25) {
  246.             free_p(bp) ;
  247.             return ;
  248.         }
  249.     }
  250.         
  251.     if (--n3hdr.ttl == 0) {    /* the packet's time to live is over! */
  252.         free_p(bp) ;
  253.         return ;
  254.     }
  255.  
  256.     /* allocate and fill PID mbuf */
  257.     if ((pbp = alloc_mbuf(1)) == NULLBUF) {
  258.         free_p(bp) ;
  259.         return ;
  260.     }
  261.     pbp->cnt = 1 ;
  262.     *pbp->data = (PID_FIRST | PID_LAST | PID_NETROM) ;
  263.  
  264.     /* now format network header */
  265.     if ((hbp = htonnr3(&n3hdr)) == NULLBUF) {
  266.         free_p(pbp) ;
  267.         free_p(bp) ;
  268.         return ;
  269.     }
  270.  
  271.     append(&pbp,hbp) ;        /* append header to pid */
  272.     append(&pbp,bp) ;        /* append data to header */
  273.     send_ax25(axp,pbp) ;    /* pass it off to ax25 code */
  274. }
  275.     
  276.  
  277. /* Perform a nodes broadcast on interface # ifno in the net/rom
  278.  * interface table.
  279.  */
  280.  
  281. nr_bcnodes(ifno)
  282. unsigned ifno ;
  283. {
  284.     struct mbuf *hbp, *dbp, *savehdr ;
  285.     struct nrroute_tab *rp ;
  286.     struct nrnbr_tab *np ;
  287.     struct nr_bind * bp ;
  288.     struct nr3dest nrdest ;
  289.     int i, didsend = 0, numdest = 0 ;
  290.     register char *cp ;
  291.     struct interface *axif = nrifaces[ifno].interface ;
  292.     struct nr_bind *find_best() ;
  293.     
  294.     /* prepare the header */
  295.     if ((hbp = alloc_mbuf(NR3NODEHL)) == NULLBUF)
  296.         return ;
  297.         
  298.     hbp->cnt = NR3NODEHL ;    
  299.     
  300.     *hbp->data = NR3NODESIG ;
  301.     memcpy(hbp->data+1,nrifaces[ifno].alias,ALEN) ;
  302.  
  303.     /* Some people don't want to advertise any routes; they
  304.      * just want to be a terminal node.  In that case we just
  305.      * want to send our call and alias and be done with it.
  306.      */
  307.  
  308.     if (!nr_verbose) {
  309.         (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  310.                          (PID_FIRST | PID_LAST | PID_NETROM),
  311.                          hbp) ;    /* send it */
  312.         return ;
  313.     }
  314.     
  315.     /* make a copy of the header in case we need to send more than */
  316.     /* one packet */
  317.     savehdr = copy_p(hbp,NR3NODEHL) ;
  318.  
  319.     /* now scan through the routing table, finding the best routes */
  320.     /* and their neighbors.  create destination subpackets and append */
  321.     /* them to the header */
  322.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  323.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  324.             /* look for best, non-obsolescent route */
  325.             if ((bp = find_best(rp->routes,0)) == NULLNRBIND)
  326.                 continue ;    /* no non-obsolescent routes found */
  327.             if (bp->quality == 0)    /* this is a loopback route */
  328.                 continue ;            /* we never broadcast these */
  329.             np = bp->via ;
  330.             /* insert best neighbor */
  331.             memcpy(nrdest.neighbor.call,np->call,ALEN) ;
  332.             nrdest.neighbor.ssid = np->call[ALEN] ;
  333.             /* insert destination from route table */
  334.             nrdest.dest = rp->call ;
  335.             /* insert alias from route table */
  336.             strcpy(nrdest.alias,rp->alias) ;
  337.             /* insert quality from binding */
  338.             nrdest.quality = bp->quality ;
  339.             /* create a network format destination subpacket */
  340.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  341.                 free_p(hbp) ;    /* drop the whole idea ... */
  342.                 free_p(savehdr) ;
  343.                 return ;
  344.             }
  345.             append(&hbp,dbp) ;    /* append to header and others */
  346.             /* see if we have appended as many destinations */
  347.             /* as we can fit into a single broadcast.  If we */
  348.             /* have, go ahead and send them out. */
  349.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  350.                 didsend = 1 ;    /* indicate that we did broadcast */
  351.                 numdest = 0 ;    /* reset the destination counter */
  352.                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  353.                                  (PID_FIRST | PID_LAST | PID_NETROM),
  354.                                  hbp) ;    /* send it */
  355.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  356.             }
  357.         }
  358.     }
  359.  
  360.     /* Now, here is something totally weird.  If our interfaces */
  361.     /* have different callsigns than this one, advertise a very */
  362.     /* high quality route to them.  Is this a good idea?  I don't */
  363.     /* know.  However, it allows us to simulate a bunch of net/roms */
  364.     /* hooked together with a diode matrix coupler. */
  365.     for (i = 0 ; i < nr_numiface ; i++) {
  366.         if (i == ifno)
  367.             continue ;        /* don't bother with ours */
  368.         cp = nrifaces[i].interface->hwaddr ;
  369.         if (!addreq((struct ax25_addr *)axif->hwaddr,cp)) {
  370.             /* both destination and neighbor address */
  371.             memcpy(&nrdest.dest,cp,AXALEN) ;
  372.             memcpy(&nrdest.neighbor,cp,AXALEN) ;
  373.             /* alias of the interface */
  374.             strcpy(nrdest.alias,nrifaces[i].alias) ;
  375.             /* and the very highest quality */
  376.             nrdest.quality = 255 ;
  377.             /* create a network format destination subpacket */
  378.             if ((dbp = htonnrdest(&nrdest)) == NULLBUF) {
  379.                 free_p(hbp) ;    /* drop the whole idea ... */
  380.                 free_p(savehdr) ;
  381.                 return ;
  382.             }
  383.             append(&hbp,dbp) ;    /* append to header and others */
  384.             if (++numdest == NRDESTPERPACK) {    /* filled it up */
  385.                 didsend = 1 ;    /* indicate that we did broadcast */
  386.                 numdest = 0 ;    /* reset the destination counter */
  387.                 (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  388.                                  (PID_FIRST | PID_LAST | PID_NETROM),
  389.                                  hbp) ;    /* send it */
  390.                 hbp = copy_p(savehdr,NR3NODEHL) ;    /* new header */
  391.             }
  392.         }
  393.     }
  394.             
  395.     /* If we have a partly filled packet left over, or we never */
  396.     /* sent one at all, we broadcast: */
  397.     if (!didsend || numdest > 0)
  398.         (*axif->output)(axif, (char *)&nr_nodebc, axif->hwaddr,
  399.                         (PID_FIRST | PID_LAST | PID_NETROM), hbp) ;
  400.  
  401.     free_p(savehdr) ;    /* free the header copy */
  402. }
  403.  
  404.  
  405. /* initialize fake arp entry for netrom */
  406. nr3arp()
  407. {
  408.     int psax25(), setpath() ;
  409.  
  410.     arp_init(ARP_NETROM,AXALEN,0,0,NULLCHAR,psax25,setpath) ;
  411. }
  412.  
  413. /* attach the net/rom interface.  no parms for now. */
  414. nr_attach(argc,argv)
  415. int argc ;
  416. char *argv[] ;
  417. {
  418.     if (nr_interface != (struct interface *)0) {
  419.         printf("netrom interface already attached\n") ;
  420.         return -1 ;
  421.     }
  422.  
  423.     nr3arp() ;
  424.     
  425.     nr_interface = (struct interface *)calloc(1,sizeof(struct interface)) ;
  426.     nr_interface->name = "netrom" ;
  427.     nr_interface->mtu = NR4MAXINFO ;
  428.     nr_interface->send = nr_send ;
  429.     nr_interface->next = ifaces ;
  430.     ifaces = nr_interface ;
  431.     return 0 ;
  432. }
  433.  
  434. /* This function checks an ax.25 address and interface number against
  435.  * the filter table and mode, and returns 1 if the address is to be
  436.  * accepted, and 0 if it is to be filtered out.
  437.  */
  438. static int
  439. accept_bc(addr,ifnum)
  440. struct ax25_addr *addr ;
  441. unsigned ifnum ;
  442. {
  443.     struct nrnf_tab *fp ;
  444.  
  445.     if (nr_nfmode == NRNF_NOFILTER)        /* no filtering in effect */
  446.         return 1 ;
  447.  
  448.     fp = find_nrnf(addr,ifnum) ;        /* look it up */
  449.     
  450.     if ((fp != NULLNRNFTAB && nr_nfmode == NRNF_ACCEPT)
  451.         || (fp == NULLNRNFTAB && nr_nfmode == NRNF_REJECT))
  452.         return 1 ;
  453.     else
  454.         return 0 ;
  455. }
  456.  
  457.  
  458. /* receive and process node broadcasts. */
  459. nr_nodercv(interface,source,bp)
  460. struct interface *interface ;
  461. struct ax25_addr *source ;
  462. struct mbuf *bp ;
  463. {
  464.     register int ifnum ;
  465.     char bcalias[7] ;
  466.     char buf[16] ;
  467.     struct nr3dest ds ;
  468.     char sbuf[AXALEN*3] ;
  469.     
  470.     /* First, see if this is even a net/rom interface: */
  471.     for (ifnum = 0 ; ifnum < nr_numiface ; ifnum++)
  472.         if (interface == nrifaces[ifnum].interface)
  473.             break ;
  474.             
  475.     if (ifnum == nr_numiface) {    /* not in the interface table */
  476.         free_p(bp) ;
  477.         return ;
  478.     }
  479.  
  480.     if (!accept_bc(source,ifnum)) {    /* check against filter */
  481.         free_p(bp) ;
  482.         return ;
  483.     }
  484.     
  485.     /* See if it has a routing broadcast signature: */
  486.     if (uchar(pullchar(&bp)) != NR3NODESIG) {
  487.         free_p(bp) ;
  488.         return ;
  489.     }
  490.  
  491.     /* now try to get the alias */
  492.     if (pullup(&bp,bcalias,ALEN) < ALEN) {
  493.         free_p(bp) ;
  494.         return ;
  495.     }
  496.  
  497.     bcalias[ALEN] = '\0' ;        /* null terminate */
  498.  
  499.     /* copy source address and convert to arp format */
  500.     memcpy(sbuf,source->call,ALEN) ;
  501.     sbuf[ALEN] = (source->ssid | E) ;    /* terminate */
  502.     
  503.     /* enter the neighbor into our routing table */
  504.     if (nr_routeadd(bcalias,source,ifnum,nrifaces[ifnum].quality,
  505.                     sbuf, 0, 0) == -1) {
  506.         free_p(bp) ;
  507.         return ;
  508.     }
  509.     
  510.     /* we've digested the header; now digest the actual */
  511.     /* routing information */
  512.     while (ntohnrdest(&ds,&bp) != -1) {
  513.         /* ignore routes to me! */
  514.         if (ismycall(&ds.dest))
  515.             continue ;
  516.         /* ignore routes below the minimum quality threshhold */
  517.         if (ds.quality < nr_autofloor)
  518.             continue ;
  519.         /* set loopback paths to 0 quality */
  520.         if (ismycall(&ds.neighbor))
  521.             ds.quality = 0 ;
  522.         else
  523.             ds.quality = ((ds.quality * nrifaces[ifnum].quality + 128)
  524.                           / 256) & 0xff ;
  525.         if (nr_routeadd(ds.alias,&ds.dest,ifnum,ds.quality,sbuf,0,0)
  526.             == -1)
  527.             break ;
  528.     }
  529.             
  530.     free_p(bp) ;    /* This will free the mbuf if anything fails above */
  531. }
  532.  
  533.  
  534. /* The following are utilities for manipulating the routing table */
  535.  
  536. /* hash function for callsigns.  Look familiar? */
  537. int16
  538. nrhash(s)
  539. struct ax25_addr *s ;
  540. {
  541.     register char x ;
  542.     register int i ;
  543.     register char *cp ;
  544.  
  545.     x = 0 ;
  546.     cp = s->call ;
  547.     for (i = ALEN ; i !=0 ; i--)
  548.         x ^= *cp++ & 0xfe ;
  549.     x ^= s->ssid & SSID ;
  550.     return uchar(x) % NRNUMCHAINS ;
  551. }
  552.  
  553. /* Find a neighbor table entry.  Neighbors are determined by
  554.  * their callsign and the interface number.  This takes care
  555.  * of the case where the same switch or hosts uses the same
  556.  * callsign on two different channels.  This isn't done by
  557.  * net/rom, but it might be done by stations running *our*
  558.  * software.
  559.  */
  560. struct nrnbr_tab *
  561. find_nrnbr(addr,ifnum)
  562. register struct ax25_addr *addr ;
  563. unsigned ifnum ;
  564. {
  565.     int16 hashval ;
  566.     register struct nrnbr_tab *np ;
  567.     char i_state ;
  568.     struct ax25_addr ncall ;
  569.  
  570.     /* Find appropriate hash chain */
  571.     hashval = nrhash(addr) ;
  572.  
  573.     /* search hash chain */
  574.     i_state = disable() ;
  575.     for (np = nrnbr_tab[hashval] ; np != NULLNTAB ; np = np->next) {
  576.         memcpy(ncall.call,np->call,ALEN) ;    /* convert first in */
  577.         ncall.ssid = np->call[ALEN] ; /* list to ax25 address format */
  578.         if (addreq(&ncall,addr) && np->interface == ifnum) {
  579.             restore(i_state) ;
  580.             return np ;
  581.         }
  582.     }
  583.     restore(i_state) ;
  584.     return NULLNTAB ;
  585. }
  586.  
  587.  
  588. /* Find a route table entry */
  589. struct nrroute_tab *
  590. find_nrroute(addr)
  591. register struct ax25_addr *addr ;
  592. {
  593.     int16 hashval ;
  594.     register struct nrroute_tab *rp ;
  595.     char i_state ;
  596.  
  597.     /* Find appropriate hash chain */
  598.     hashval = nrhash(addr) ;
  599.  
  600.     /* search hash chain */
  601.     i_state = disable() ;
  602.     for (rp = nrroute_tab[hashval] ; rp != NULLNRRTAB ; rp = rp->next) {
  603.         if (addreq(&rp->call,addr)) {
  604.             restore(i_state) ;
  605.             return rp ;
  606.         }
  607.     }
  608.     restore(i_state) ;
  609.     return NULLNRRTAB ;
  610. }
  611.  
  612. /* Try to find the AX.25 address of a node with the given alias.  Return */
  613. /* a pointer to the AX.25 address if found, otherwise NULLAXADDR.  The alias */
  614. /* should be a six character, blank-padded, upper-case string. */
  615.  
  616. struct ax25_addr *
  617. find_nralias(alias)
  618. char *alias ;
  619. {
  620.     int i ;
  621.     register struct nrroute_tab *rp ;
  622.  
  623.     /* Since the route entries are hashed by ax.25 address, we'll */
  624.     /* have to search all the chains */
  625.     
  626.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  627.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next)
  628.             if (strncmp(alias, rp->alias, 6) == 0)
  629.                 return &rp->call ;
  630.  
  631.     /* If we get to here, we're out of luck */
  632.  
  633.     return NULLAXADDR ;
  634. }
  635.  
  636.     
  637. /* Find a binding in a list by its neighbor structure's address */
  638. struct nr_bind *
  639. find_binding(list,neighbor)
  640. struct nr_bind *list ;
  641. register struct nrnbr_tab *neighbor ;
  642. {
  643.     register struct nr_bind *bp ;
  644.  
  645.     for(bp = list ; bp != NULLNRBIND ; bp = bp->next)
  646.         if (bp->via == neighbor)
  647.             return bp ;
  648.  
  649.     return NULLNRBIND ;
  650. }
  651.  
  652. /* Find the worst quality non-permanent binding in a list */
  653. static
  654. struct nr_bind *
  655. find_worst(list)
  656. struct nr_bind *list ;
  657. {
  658.     register struct nr_bind *bp ;
  659.     struct nr_bind *worst = NULLNRBIND ;
  660.     unsigned minqual = 1000 ;     /* infinity */
  661.  
  662.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  663.         if (!(bp->flags & NRB_PERMANENT) && bp->quality < minqual) {
  664.             worst = bp ;
  665.             minqual = bp->quality ;
  666.         }
  667.  
  668.     return worst ;
  669. }
  670.  
  671. /* Find the best binding of any sort in a list.  If obso is 1,
  672.  * include entries below the obsolescence threshhold in the
  673.  * search (used when this is called for routing broadcasts).
  674.  * If it is 0, routes below the threshhold are treated as
  675.  * though they don't exist.
  676.  */
  677. static
  678. struct nr_bind *
  679. find_best(list,obso)
  680. struct nr_bind *list ;
  681. unsigned obso ;
  682. {
  683.     register struct nr_bind *bp ;
  684.     struct nr_bind *best = NULLNRBIND ;
  685.     int maxqual = -1 ;    /* negative infinity */
  686.  
  687.     for (bp = list ; bp != NULLNRBIND ; bp = bp->next)
  688.         if ((int)bp->quality > maxqual)
  689.             if (obso || bp->obsocnt >= obso_minbc) {
  690.                 best = bp ;
  691.                 maxqual = bp->quality ;
  692.             }
  693.  
  694.     return best ;
  695. }
  696.  
  697. /* Add a route to the net/rom routing table */
  698. nr_routeadd(alias,dest,ifnum,quality,neighbor,permanent,record)
  699. char *alias ;                /* net/rom node alias, blank-padded and */
  700.                             /* null-terminated */
  701. struct ax25_addr *dest ;    /* destination node callsign */
  702. unsigned ifnum ;            /* net/rom interface number */
  703. unsigned quality ;            /* route quality */
  704. char *neighbor ;            /* neighbor node + 2 digis (max) in arp format */
  705. unsigned permanent ;        /* 1 if route is permanent (hand-entered) */
  706. unsigned record ;            /* 1 if route is a "record route" */
  707. {
  708.     struct nrroute_tab *rp ;
  709.     struct nr_bind *bp ;
  710.     struct nrnbr_tab *np ;
  711.     int16 rhash, nhash ;
  712.     struct ax25_addr ncall ;
  713.  
  714.     /* See if a routing table entry exists for this destination */
  715.     if ((rp = find_nrroute(dest)) == NULLNRRTAB) {
  716.         if ((rp =
  717.              (struct nrroute_tab *)calloc(1,sizeof(struct nrroute_tab)))
  718.             == NULLNRRTAB)
  719.             return -1 ;
  720.         else {            /* create a new route table entry */
  721.             strncpy(rp->alias,alias,6) ;
  722.             rp->call = *dest ;
  723.             rhash = nrhash(dest) ;
  724.             rp->next = nrroute_tab[rhash] ;
  725.             if (rp->next != NULLNRRTAB)
  726.                 rp->next->prev = rp ;
  727.             nrroute_tab[rhash] = rp ;    /* link at head of hash chain */
  728.         }
  729.     } else if (!record) {
  730.         strncpy(rp->alias,alias,6) ;    /* update the alias */
  731.     }
  732.  
  733.     /* See if an entry exists for this neighbor */
  734.     memcpy(ncall.call,neighbor,ALEN) ;    /* no digis included */
  735.     ncall.ssid = neighbor[ALEN] ;
  736.     if ((np = find_nrnbr(&ncall,ifnum)) == NULLNTAB) {
  737.         if ((np =
  738.              (struct nrnbr_tab *)calloc(1,sizeof(struct nrnbr_tab)))
  739.              == NULLNTAB) {
  740.             if (rp->num_routes == 0) {    /* we just added to table */
  741.                 nrroute_tab[rhash] = rp->next ;
  742.                 free(rp) ;                /* so get rid of it */
  743.             }
  744.             return -1 ;
  745.         }
  746.         else {        /* create a new neighbor entry */
  747.             memcpy(np->call,neighbor,3 * AXALEN) ;
  748.             np->interface = ifnum ;
  749.             nhash = nrhash(&ncall) ;
  750.             np->next = nrnbr_tab[nhash] ;
  751.             if (np->next != NULLNTAB)
  752.                 np->next->prev = np ;
  753.             nrnbr_tab[nhash] = np ;
  754.         }
  755.     }
  756.     else if (permanent) {        /* force this path to the neighbor */
  757.         memcpy(np->call,neighbor,3 * AXALEN) ;
  758.     }
  759.         
  760.     /* See if there is a binding between the dest and neighbor */
  761.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND) {
  762.         if ((bp =
  763.              (struct nr_bind *)calloc(1,sizeof(struct nr_bind)))
  764.             == NULLNRBIND) {
  765.             if (rp->num_routes == 0) {    /* we just added to table */
  766.                 nrroute_tab[rhash] = rp->next ;
  767.                 free(rp) ;                /* so get rid of it */
  768.             }
  769.             if (np->refcnt == 0) {        /* we just added it */
  770.                 nrnbr_tab[nhash] = np->next ;
  771.                 free(np) ;
  772.             }
  773.             return -1 ;
  774.         }
  775.         else {        /* create a new binding and link it in */
  776.             bp->via = np ;    /* goes via this neighbor */
  777.             bp->next = rp->routes ;    /* link into binding chain */
  778.             if (bp->next != NULLNRBIND)
  779.                 bp->next->prev = bp ;
  780.             rp->routes = bp ;
  781.             rp->num_routes++ ;    /* bump route count */
  782.             np->refcnt++ ;        /* bump neighbor ref count */
  783.             bp->quality = quality ;
  784.             bp->obsocnt = obso_init ;    /* use initial value */
  785.             if (permanent)
  786.                 bp->flags |= NRB_PERMANENT ;
  787.             else if (record)    /* notice permanent overrides record! */
  788.                 bp->flags |= NRB_RECORDED ;
  789.         }
  790.     } else {
  791.         if (permanent) {    /* permanent request trumps all */
  792.             bp->quality = quality ;
  793.             bp->obsocnt = obso_init ;
  794.             bp->flags |= NRB_PERMANENT ;
  795.             bp->flags &= ~NRB_RECORDED ;    /* perm is not recorded */
  796.         } else if (!(bp->flags & NRB_PERMANENT)) {    /* not permanent */
  797.             if (record) {    /* came from nr_route */
  798.                 if (bp->flags & NRB_RECORDED) { /* no mod non-rec bindings */
  799.                     bp->quality = quality ;
  800.                     bp->obsocnt = obso_init ; /* freshen recorded routes */
  801.                 }
  802.             } else {        /* came from a routing broadcast */
  803.                 bp->quality = quality ;
  804.                 bp->obsocnt = obso_init ;
  805.                 bp->flags &= ~NRB_RECORDED ; /* no longer a recorded route */
  806.             }
  807.         }
  808.     }
  809.         
  810.     /* Now, check to see if we have too many bindings, and drop */
  811.     /* the worst if we do */
  812.     if (rp->num_routes > nr_maxroutes) {
  813.         /* since find_worst never returns permanent entries, the */
  814.         /* limitation on number of routes is circumvented for    */
  815.         /* permanent routes */
  816.         if ((bp = find_worst(rp->routes)) != NULLNRBIND) {
  817.             memcpy(ncall.call,bp->via->call,ALEN) ;
  818.             ncall.ssid = bp->via->call[ALEN] ;
  819.             nr_routedrop(dest,&ncall,bp->via->interface) ;
  820.         }
  821.     }
  822.  
  823.     return 0 ;
  824. }
  825.  
  826.  
  827. /* Drop a route to dest via neighbor */
  828. nr_routedrop(dest,neighbor,ifnum)
  829. struct ax25_addr *dest, *neighbor ;
  830. unsigned ifnum ;
  831. {
  832.     register struct nrroute_tab *rp ;
  833.     register struct nrnbr_tab *np ;
  834.     register struct nr_bind *bp ;
  835.  
  836.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  837.         return -1 ;
  838.  
  839.     if ((np = find_nrnbr(neighbor,ifnum)) == NULLNTAB)
  840.         return -1 ;
  841.  
  842.     if ((bp = find_binding(rp->routes,np)) == NULLNRBIND)
  843.         return -1 ;
  844.  
  845.     /* drop the binding first */
  846.     if (bp->next != NULLNRBIND)
  847.         bp->next->prev = bp->prev ;
  848.     if (bp->prev != NULLNRBIND)
  849.         bp->prev->next = bp->next ;
  850.     else
  851.         rp->routes = bp->next ;
  852.  
  853.     free(bp) ;
  854.     rp->num_routes-- ;        /* decrement the number of bindings */
  855.     np->refcnt-- ;            /* and the number of neighbor references */
  856.     
  857.     /* now see if we should drop the route table entry */
  858.     if (rp->num_routes == 0) {
  859.         if (rp->next != NULLNRRTAB)
  860.             rp->next->prev = rp->prev ;
  861.         if (rp->prev != NULLNRRTAB)
  862.             rp->prev->next = rp->next ;
  863.         else
  864.             nrroute_tab[nrhash(dest)] = rp->next ;
  865.  
  866.         free(rp) ;
  867.     }
  868.  
  869.     /* and check to see if this neighbor can be dropped */
  870.     if (np->refcnt == 0) {
  871.         if (np->next != NULLNTAB)
  872.             np->next->prev = np->prev ;
  873.         if (np->prev != NULLNTAB)
  874.             np->prev->next = np->next ;
  875.         else
  876.             nrnbr_tab[nrhash(neighbor)] = np->next ;
  877.  
  878.         free(np) ;
  879.     }
  880.     
  881.     return 0 ;
  882. }
  883.  
  884. /* Find the best neighbor for destination dest, in arp format */
  885. char *
  886. nr_getroute(dest)
  887. struct ax25_addr *dest ;
  888. {
  889.     register struct nrroute_tab *rp ;
  890.     register struct nr_bind *bp ;
  891.  
  892.     if ((rp = find_nrroute(dest)) == NULLNRRTAB)
  893.         return NULLCHAR ;
  894.  
  895.     if ((bp = find_best(rp->routes)) == NULLNRBIND)    /* shouldn't happen! */
  896.         return NULLCHAR ;
  897.  
  898.     return bp->via->call ;
  899. }
  900.  
  901. /* Find an entry in the filter table */
  902. struct nrnf_tab *
  903. find_nrnf(addr,ifnum)
  904. register struct ax25_addr *addr ;
  905. unsigned ifnum ;
  906. {
  907.     int16 hashval ;
  908.     register struct nrnf_tab *fp ;
  909.  
  910.     /* Find appropriate hash chain */
  911.     hashval = nrhash(addr) ;
  912.  
  913.     /* search hash chain */
  914.     for (fp = nrnf_tab[hashval] ; fp != NULLNRNFTAB ; fp = fp->next) {
  915.         if (addreq(&fp->neighbor,addr) && fp->interface == ifnum) {
  916.             return fp ;
  917.         }
  918.     }
  919.  
  920.     return NULLNRNFTAB ;
  921. }
  922.  
  923. /* Add an entry to the filter table.  Return 0 on success,
  924.  * -1 on failure
  925.  */
  926. int
  927. nr_nfadd(addr,ifnum)
  928. struct ax25_addr *addr ;
  929. unsigned ifnum ;
  930. {
  931.     struct nrnf_tab *fp ;
  932.     int16 hashval ;
  933.     
  934.     if (find_nrnf(addr,ifnum) != NULLNRNFTAB)
  935.         return 0 ;    /* already there; it's a no-op */
  936.  
  937.     if ((fp = (struct nrnf_tab *)calloc(1,sizeof(struct nrnf_tab)))
  938.         == NULLNRNFTAB)
  939.         return -1 ;    /* no storage */
  940.  
  941.     hashval = nrhash(addr) ;
  942.     fp->neighbor = *addr ;
  943.     fp->interface = ifnum ;
  944.     fp->next = nrnf_tab[hashval] ;
  945.     if (fp->next != NULLNRNFTAB)
  946.         fp->next->prev = fp ;
  947.     nrnf_tab[hashval] = fp ;
  948.  
  949.     return 0 ;
  950. }
  951.  
  952. /* Drop a neighbor from the filter table.  Returns 0 on success, -1
  953.  * on failure.
  954.  */
  955. int
  956. nr_nfdrop(addr,ifnum)
  957. struct ax25_addr *addr ;
  958. unsigned ifnum ;
  959. {
  960.     struct nrnf_tab *fp ;
  961.  
  962.     if ((fp = find_nrnf(addr,ifnum)) == NULLNRNFTAB)
  963.         return -1 ;    /* not in the table */
  964.  
  965.     if (fp->next != NULLNRNFTAB)
  966.         fp->next->prev = fp->prev ;
  967.     if (fp->prev != NULLNRNFTAB)
  968.         fp->prev->next = fp->next ;
  969.     else
  970.         nrnf_tab[nrhash(addr)] = fp->next ;
  971.  
  972.     free(fp) ;
  973.  
  974.     return 0 ;
  975. }
  976.  
  977.